Skip to content

test(interop): preserve interop regression-suite fixes + update README#83

Merged
torlando-tech merged 4 commits into
mainfrom
fix/interop-regression-suite
Jun 1, 2026
Merged

test(interop): preserve interop regression-suite fixes + update README#83
torlando-tech merged 4 commits into
mainfrom
fix/interop-regression-suite

Conversation

@torlando-tech

Copy link
Copy Markdown
Owner

Test-only follow-up. These interop-harness fixes were developed while validating the dual-backend stack on-device but landed after #81 was already merged, so they didn't make it into main (the suite there still has the old [PY] diag prefix and would error at setup). Reapplied here onto main. No production code — only Tests/interop/.

What's included:

  • Match the renamed [RNS] diag-log prefix (was [PY]). The dual-backend refactor renamed the backend-agnostic log prefix; the harness regexes/asserts were stale and errored the whole suite at setup.
  • Auto-seed the lxmd TCP-client interface (conftest._ensure_rnsd_interface). A fresh sim comes up with 0 RNS interfaces; the fixture now seeds 127.0.0.1:4242 into Columba's interface store + relaunches, so the suite is self-contained (no manual "Add Interface"). Override via RNSD_TCP_HOST/RNSD_TCP_PORT.
  • Pin lxmd's propagation node so test_image_..._propagated runs deterministically instead of skipping on lxmd's 5-min announce cadence; fix Sideband teardown (_exit_handlercleanup(), removed upstream).
  • README: corrected topology (lxmd — not rnsd — owns the shared instance + :4242 TCPServer), documented the automated run (pytest -v, 14 cases), and added a troubleshooting section (incl. the wedged-lxmd symptom + launchctl kickstart fix).

Verified: from a wiped-interface sim, the fixtures seed everything and the full suite is 14 passed, 0 skipped.

@greptile-apps

greptile-apps Bot commented May 31, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Test-only follow-up that reapplies three interop-harness fixes that missed the #81 merge window: stale [PY][RNS] log-prefix regexes, missing auto-seeding of the lxmd TCP-client interface on fresh sims, and the wrong SidebandCore teardown call (_exit_handlercleanup()).

  • [PY][RNS] sweep — four files updated; all regex patterns, string predicates, docstrings, and comments now reference the backend-agnostic [RNS] prefix.
  • _ensure_rnsd_interface + _ensure_sim_interface fixture — seeds Columba's UserDefaults interface store via plistlib, bounces cfprefsd, relaunches the app, and confirms success by polling diag.log. Makes the suite self-contained on a fresh sim install.
  • Prop-node pinning in _bootstrap_paths — calls lxmd --status to discover the propagation-node hash and injects it into sim._cached_propagation_node_hex, eliminating the 5-min announce-cadence race.

Confidence Score: 5/5

Test-only change with no production code touched; safe to merge.

All changes are confined to Tests/interop/. The [PY] to [RNS] prefix updates are mechanical and consistent across all four affected files. The new _ensure_rnsd_interface logic is well-guarded and the developer verified a full 14/0 pass run from a clean sim. The SidebandCore teardown swap is a straightforward API alignment.

Tests/interop/conftest.py — _lxmd_propagation_hex passes --timeout 10 to lxmd --status; if that flag is not recognised the propagated test silently skips with a misleading warning.

Important Files Changed

Filename Overview
Tests/interop/conftest.py Major additions: _ensure_rnsd_interface (plist-based interface seeding + cfprefsd kick), _lxmd_propagation_hex (lxmd --status query), _ensure_sim_interface fixture, and prop-node pinning in _bootstrap_paths. All [PY] diag-log prefix regexes updated to [RNS].
Tests/interop/peer_sideband.py SidebandPeer.stop() updated from the removed _exit_handler() to the current cleanup() API, with the same guard-and-warn pattern as the rest of the file.
Tests/interop/run_peer.py Comment-only change: [PY] to [RNS] in two inline documentation strings; no logic touched.
Tests/interop/test_attachments.py _wait_for_diag_inbound updated to match the renamed [RNS] inbound prefix in both the docstring and the string-search predicate.
Tests/interop/README.md Topology corrected (lxmd owns the shared RNS instance + :4242 TCPServer, not rnsd), prerequisites and run instructions updated for the now-automated suite, troubleshooting section added.

Sequence Diagram

sequenceDiagram
    participant pytest
    participant sim as sim fixture
    participant esi as _ensure_sim_interface
    participant bp as _bootstrap_paths
    participant sb as sideband fixture
    participant lxmd
    participant Columba as Columba.app (sim)
    participant Sideband as SidebandPeer

    pytest->>sim: create Simulator(udid)
    sim-->>pytest: Simulator instance
    pytest->>sb: SidebandPeer.start()
    sb-->>pytest: peer ready
    pytest->>esi: _ensure_rnsd_interface(udid)
    esi->>Columba: simctl terminate
    esi->>esi: write com.columba.interfaces plist
    esi->>Columba: kickstart cfprefsd
    esi->>Columba: simctl launch
    esi->>Columba: poll diag.log for [RNS] wrote config
    Columba-->>esi: N interfaces registered
    pytest->>bp: _bootstrap_paths(sim, sideband, _ensure_sim_interface)
    bp->>Sideband: lxmf_destination.announce()
    bp->>Columba: lxma://test-announce
    loop until both paths known
        bp->>Columba: poll diag.log for Sideband announce
        bp->>Sideband: RNS.Identity.recall(ios_hex)
    end
    bp->>lxmd: lxmd --status --timeout 10
    lxmd-->>bp: Propagation Node running on hash
    bp->>sim: inject _cached_propagation_node_hex
    Note over pytest,Sideband: 14 interop tests run
Loading

Fix All in Claude Code

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
Tests/interop/conftest.py:203
**`--timeout` may not be a recognised `lxmd --status` flag**

`_sh([LXMD_BIN, "--status", "--timeout", "10"], check=False, timeout=20)` passes `--timeout` as a positional flag to `lxmd`. If the installed version of lxmd doesn't recognise `--timeout` for the `--status` subcommand, it exits non-zero immediately, `r.stdout` is empty, the regex finds nothing, and `_lxmd_propagation_hex` returns `None` — meaning `test_image_..._propagated` silently skips with a "lxmd down?" warning even though lxmd is perfectly healthy. The subprocess-level `timeout=20` and the `except Exception: return None` guard handle binary-not-found and hangs correctly, but there's no stderr check to distinguish "flag unrecognised" from "lxmd truly unreachable". Dropping `--timeout 10` (or falling back without it on `CalledProcessError`) would remove the dependency on an undocumented CLI contract.

Reviews (2): Last reviewed commit: "docs(interop): update README for the aut..." | Re-trigger Greptile

Comment thread Tests/interop/conftest.py
# start (see _ensure_rnsd_interface), so a fresh install / clean sim needs no
# manual Settings → Network Interfaces → Add step. Override for a non-default host.
RNSD_TCP_HOST = os.environ.get("RNSD_TCP_HOST", "127.0.0.1")
RNSD_TCP_PORT = int(os.environ.get("RNSD_TCP_PORT", "4242"))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 If RNSD_TCP_PORT is set to a non-integer value (e.g. accidentally including whitespace, an alphabetic character, or an empty string), int() raises a bare ValueError at module import time — before pytest collects any tests and before any fixture can emit a useful diagnostic. A try/except with a clear message gives a much better failure experience.

Suggested change
RNSD_TCP_PORT = int(os.environ.get("RNSD_TCP_PORT", "4242"))
try:
RNSD_TCP_PORT = int(os.environ.get("RNSD_TCP_PORT", "4242"))
except ValueError:
raise SystemExit(
f"RNSD_TCP_PORT={os.environ['RNSD_TCP_PORT']!r} is not a valid integer port number."
)
Prompt To Fix With AI
This is a comment left during a code review.
Path: Tests/interop/conftest.py
Line: 60

Comment:
If `RNSD_TCP_PORT` is set to a non-integer value (e.g. accidentally including whitespace, an alphabetic character, or an empty string), `int()` raises a bare `ValueError` at module import time — before pytest collects any tests and before any fixture can emit a useful diagnostic. A `try/except` with a clear message gives a much better failure experience.

```suggestion
try:
    RNSD_TCP_PORT = int(os.environ.get("RNSD_TCP_PORT", "4242"))
except ValueError:
    raise SystemExit(
        f"RNSD_TCP_PORT={os.environ['RNSD_TCP_PORT']!r} is not a valid integer port number."
    )
```

How can I resolve this? If you propose a fix, please make it concise.

Fix in Claude Code

Comment thread Tests/interop/conftest.py
Comment on lines +155 to +181
targets = [_app_data_container(udid) / "Library/Preferences" / f"{BUNDLE_ID}.plist"]
ag = _app_group_prefs_plist(udid)
if ag is not None:
targets.append(ag)
for plist_path in targets:
try:
with open(plist_path, "rb") as f:
pl = plistlib.load(f)
except Exception:
pl = {}
pl["com.columba.interfaces"] = blob # bytes -> <data>, exactly UserDefaults.set(Data)
plist_path.parent.mkdir(parents=True, exist_ok=True)
with open(plist_path, "wb") as f:
plistlib.dump(pl, f, fmt=plistlib.FMT_BINARY)

# cfprefsd caches container prefs; kick it AFTER editing so it re-reads our
# file rather than serving / flushing back the stale in-memory copy
# (mirrors clean_location_state's dance). user/501 is the sim's only scope.
subprocess.run(["xcrun", "simctl", "spawn", udid, "launchctl", "kickstart", "-k",
"user/501/com.apple.cfprefsd.xpc.daemon"], capture_output=True)
time.sleep(0.5)
subprocess.run(["xcrun", "simctl", "launch", udid, BUNDLE_ID], check=True, capture_output=True)

# Confirm the backend loaded the interface (config written with N>=1), so a
# silent seed failure surfaces here rather than as a confusing path-bootstrap
# timeout. diag.log is cleared on launch, so the match is fresh.
diag = _app_data_container(udid) / "Documents" / "diag.log"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 _app_data_container called twice per seed

_ensure_rnsd_interface shells out to xcrun simctl get_app_container at line 155 (building targets) and again at line 181 (resolving diag). Each call forks a subprocess. Capture the result once and reuse it — container = _app_data_container(udid) — to halve the subprocess overhead and keep the path consistent across both uses.

Prompt To Fix With AI
This is a comment left during a code review.
Path: Tests/interop/conftest.py
Line: 155-181

Comment:
**`_app_data_container` called twice per seed**

`_ensure_rnsd_interface` shells out to `xcrun simctl get_app_container` at line 155 (building `targets`) and again at line 181 (resolving `diag`). Each call forks a subprocess. Capture the result once and reuse it — `container = _app_data_container(udid)` — to halve the subprocess overhead and keep the path consistent across both uses.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

torlando-agent Bot and others added 4 commits May 31, 2026 21:50
The dual-backend refactor renamed the diag.log backend prefix from the
Python-specific [PY] to backend-agnostic [RNS] (AppServices logs
[RNS] started/inbound/announce/delivery), but the interop harness still
grepped [PY] — so identity_hex/lxmf_delivery_hex/auto_propagation_node_hex
and the inbound assertion never matched and the whole suite errored at
setup (_bootstrap_paths). Update conftest regexes (incl. the escaped
re.search patterns), the test_attachments inbound assert, the readiness
poll, run_peer, and comments. No production change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…d suite)

The suite assumed the sim's Columba was pre-configured with a TCP-client
interface to the host rnsd/lxmd shared instance; a fresh install came up
with 0 interfaces, so _bootstrap_paths timed out ('sim never heard the
peer announce'). Add a session-scoped autouse fixture that seeds exactly
that interface into Columba's UserDefaults interface store and relaunches,
so the regression suite needs no manual 'Add Interface' step.

InterfaceRepository persists interfaces as a JSON blob under
com.columba.interfaces (app-group suite, migrated from .standard). We write
the blob directly to the container plist(s) — simctl spawn defaults targets
the wrong (global) domain — and bounce cfprefsd so the relaunched app
re-reads it. Host/port override via RNSD_TCP_HOST/RNSD_TCP_PORT. Verified:
from a wiped-interface sim, the fixture seeds + the suite passes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… skip) + fix Sideband teardown

- test_image_..._propagated skipped whenever the sim hadn't heard lxmd's
  5-min lxmf.propagation announce yet (ordering flake). lxmd has no announce
  trigger and RNS.Transport.request_path is a no-op from a shared-instance
  process that already holds the path; a real re-announce needs an lxmd
  restart (drops the whole mesh — wrong for a regression run). Instead
  discover lxmd's prop-node hash via
LXMF Propagation Node running on <33f2621f135146ce30f0767d811af2b6>, uptime is 33m and 18.48s
Messagestore contains 3265 messages, 8.25 MB (0.41% utilised of 2.00 GB)
Required propagation stamp cost is 16, flexibility is 3
Peering cost is 18, max remote peering cost is 26
Accepting propagated messages from all nodes
256.00 KB message limit, 10.24 MB sync limit

Peers   : 17 total (peer limit is 20)
          17 discovered, 0 static
          17 available, 0 unreachable

Traffic : 8 messages received in total (2.43 KB)
          0 messages received from peered nodes (0 B)
          8 messages received from unpeered nodes (2.43 KB)
          0 messages transferred to peered nodes (0 B)
          0 propagation messages received directly from clients
          8 propagation messages served to clients
          Distribution factor is 0.0 in _bootstrap_paths
  (after sim+sideband connect) and pin it on the sim helper, so the test runs
  deterministically and still exercises the real propagated delivery path
  (sim -> lxmd store -> Sideband sync). Falls back to a warn+skip if lxmd is
  down. -> full suite now 14 passed, 0 skipped.
- peer_sideband.stop(): SidebandCore renamed teardown to cleanup() (the old
  __exit_handler is gone); call cleanup() instead so we don't leak the
  hasattr-guard warning. (Caught by the guard added last commit.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Bring the harness README in line with the working suite: lxmd (not rnsd)
owns the shared RNS instance + :4242 TCPServer (rnsd/nomadnet are clients);
the suite auto-seeds the sim's TCP interface and pins lxmd's propagation
node, so no manual interface setup; diag prefix is [RNS]; `pytest -v` is
the run command (14 cases). Add a troubleshooting section incl. the
wedged-lxmd symptom + `launchctl kickstart` fix.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@torlando-tech torlando-tech force-pushed the fix/interop-regression-suite branch from 88db1b7 to c720607 Compare June 1, 2026 01:51
@codecov

codecov Bot commented Jun 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@torlando-tech torlando-tech merged commit ce91afe into main Jun 1, 2026
3 checks passed
@torlando-tech torlando-tech deleted the fix/interop-regression-suite branch June 1, 2026 02:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant